package com.tsfyun.scm.service.impl.customer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.tsfyun.common.base.dto.FileQTO;
import com.tsfyun.common.base.dto.TaskDTO;
import com.tsfyun.common.base.enums.*;
import com.tsfyun.common.base.enums.domain.CustomerStatusEnum;
import com.tsfyun.common.base.enums.domain.DomainOprationEnum;
import com.tsfyun.common.base.enums.domain.AgreementStatusEnum;
import com.tsfyun.common.base.enums.domain.DomainTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.security.LoginVO;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.support.DomainStatus;
import com.tsfyun.common.base.util.IpUtils;
import com.tsfyun.common.base.util.LocalDateTimeUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.customer.*;
import com.tsfyun.scm.dto.customer.client.ClientServiceAgreementSignDTO;
import com.tsfyun.scm.dto.support.TaskNoticeContentDTO;
import com.tsfyun.scm.entity.customer.*;
import com.tsfyun.scm.entity.file.UploadFile;
import com.tsfyun.scm.entity.user.Person;
import com.tsfyun.scm.mapper.customer.AgreementMapper;
import com.tsfyun.scm.service.common.ICommonService;
import com.tsfyun.scm.service.customer.*;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.file.IUploadFileService;
import com.tsfyun.scm.service.support.ITaskNoticeContentService;
import com.tsfyun.scm.service.system.ISerialNumberService;
import com.tsfyun.scm.service.system.IStatusHistoryService;
import com.tsfyun.scm.service.system.ISubjectService;
import com.tsfyun.scm.service.user.IPersonService;
import com.tsfyun.scm.util.AgreementUtil;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.base.ClientFileVO;
import com.tsfyun.scm.vo.customer.*;
import com.tsfyun.scm.vo.customer.client.ClientImpQuotePlusVO;
import com.tsfyun.scm.vo.system.SubjectVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * <p>
 * 协议报价单 服务实现类
 * </p>
 *
 *
 * @since 2020-03-31
 */
@RefreshScope
@Service
@Slf4j
public class AgreementServiceImpl extends ServiceImpl<Agreement> implements IAgreementService {

    @Autowired
    private AgreementMapper agreementMapper;
    @Autowired
    private IImpQuoteService impQuoteService;
    @Autowired
    private IImpClauseService impClauseService;
    @Autowired
    private ISubjectService subjectService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IUploadFileService uploadFileService;
    @Autowired
    private IStatusHistoryService statusHistoryService;
    @Autowired
    private ICommonService commonService;
    @Autowired
    private ITaskNoticeContentService taskNoticeContentService;
    @Autowired
    private IExpressStandardQuoteService expressStandardQuoteService;
    @Autowired
    private ISerialNumberService serialNumberService;
    @Autowired
    private ICustomerExpressQuoteService customerExpressQuoteService;
    @Autowired
    private ICustomerExpressQuoteMemberService customerExpressQuoteMemberService;
    @Autowired
    private IPersonService personService;

    //文件存放目录
    @Value(value = "${file.directory}")
    private String fileDirectory;

    //默认协议版本
    @Value("${agreement.version}")
    private String agreementVersion;

    @Autowired
    private HttpServletRequest request;

    @Resource
    private RedisLockRegistry redisLockRegistry;

    @Value("${redis.lock.time:5}")
    private Integer lockTime;


    @Override
    public PageInfo<AgreementVO> list(AgreementQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        Map<String,Object> params = beanMapper.map(qto,Map.class);
        return new PageInfo<>(agreementMapper.list(params));
    }
    @Override
    public AgreementDetailPlusVO detailPlus(Long id) {
        return detailPlus(id,null);
    }

    @Override
    public AgreementDetailPlusVO detailPlus(Long id,String operation) {
        Agreement agreement = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("协议不存在"));
        //验证状态是否可以执行操作
        DomainStatus.getInstance().check(DomainOprationEnum.of(operation), agreement.getStatusId());
        AgreementDetailPlusVO vo = new AgreementDetailPlusVO();
        AgreementDetailVO agreementDetailVO = beanMapper.map(agreement,AgreementDetailVO.class);
        vo.setAgreement(agreementDetailVO);
        List<ImpQuote> impQuotes =  impQuoteService.findByAgreementId(id);
        ImpClause impClause = impClauseService.findByAgreementId(id);
        vo.setImpQuotes(beanMapper.mapAsList(impQuotes, ImpQuoteVO.class));
        vo.setImpClause(Objects.nonNull(impClause) ? beanMapper.map(impClause, ImpClauseVO.class) : null);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addPlus(AgreemenPlusDTO dto) {
        //获取甲方(客户)
        Customer customer = customerService.findByNameWithRight(dto.getAgreement().getPartyaName());
        // 根据客户查询是否有存在未完成的报价
        if(agreementMapper.countUndone(customer.getId())>0){
            throw new ServiceException("当前客户已经存在未完成的报价，不允许新建");
        }
        Agreement agreement = beanMapper.map(dto.getAgreement(),Agreement.class);
        agreement.setCustomerId(customer.getId());
        agreement.setPartyaName(customer.getName());
        agreement.setPartyaSocialNo(customer.getSocialNo());
        agreement.setPartyaLegalPerson(customer.getLegalPerson());
        agreement.setPartyaTel(customer.getTel());
        agreement.setPartyaFax(customer.getFax());
        agreement.setPartyaAddress(customer.getAddress());
        //获取乙方(主体公司)
        SubjectVO subjectVO = subjectService.findByCode();
        TsfPreconditions.checkArgument(Objects.nonNull(subjectVO),new ServiceException("获取乙方信息失败"));
        agreement.setPartybName(subjectVO.getName());
        agreement.setPartybSocialNo(subjectVO.getSocialNo());
        agreement.setPartybLegalPerson(subjectVO.getLegalPerson());
        agreement.setPartybTel(subjectVO.getTel());
        agreement.setPartybFax(subjectVO.getFax());
        agreement.setPartybAddress(subjectVO.getAddress());
        agreement.setPartybRegAddress(subjectVO.getRegAddress());
        agreement.setIsSignBack(Boolean.FALSE);
        //实际失效时间
        agreement.setActualInvalidDate(agreement.getInvalidDate());
        if(agreement.getDelayYear()>0){
            agreement.setActualInvalidDate(agreement.getActualInvalidDate().plusYears(agreement.getDelayYear()));
        }
        List<ImpQuoteDTO> impQuotes = dto.getImpQuotes();
        TsfPreconditions.checkArgument(CollUtil.isNotEmpty(impQuotes),new ServiceException("请至少选择一种账期报价"));
        agreement.setQuoteDescribe(impQuoteService.quoteDescribe(beanMapper.mapAsList(impQuotes,ImpQuote.class)));
        AgreementStatusEnum statusEnum = Objects.equals(Boolean.TRUE,dto.getAgreement().getSubmitAudit())?AgreementStatusEnum.WAIT_EXAMINE:AgreementStatusEnum.SAVED;
        agreement.setStatusId(statusEnum.getCode());
        // 协议版本
        agreement.setVersion(agreementVersion);
        //代理进口 - 代理只能双抬头
        BusinessTypeEnum IMP_AGENT = BusinessTypeEnum.IMP_AGENT;
        if(IMP_AGENT == BusinessTypeEnum.of(agreement.getBusinessType())){
            DeclareTypeEnum SINGLE = DeclareTypeEnum.SINGLE;//单抬头
            TsfPreconditions.checkArgument(SINGLE != DeclareTypeEnum.of(agreement.getDeclareType()),new ServiceException(String.format("%s业务不能选择%s报关",IMP_AGENT.getName(),SINGLE.getName())));
        }
        //协议约定
        ImpClauseDTO impClauseDTO = dto.getImpClause();
        // 甲方缴税只能做代理进口业务
        if(Objects.equals(VoluntarilyTaxEnum.PARTYA,VoluntarilyTaxEnum.of(impClauseDTO.getVoluntarilyTax())) && !Objects.equals(IMP_AGENT,BusinessTypeEnum.of(agreement.getBusinessType()))){
            throw new ServiceException("甲方缴税业务类型只能为代理进口");
        }
        try{
            super.saveNonNull(agreement);

            //记录历史状态
            statusHistoryService.saveHistory(DomainOprationEnum.AREEMENT_ADD,
                    agreement.getId().toString(),Agreement.class.getName(),
                    statusEnum.getCode(),statusEnum.getName(),
                    Objects.equals(AgreementStatusEnum.SAVED,statusEnum)?"临时保存":"提交审核"
            );
        }catch (DuplicateKeyException e) {
            if(e.getMessage().contains("UK_agreement_doc_no")) {
                throw new ServiceException("协议编号已经存在请修改");
            }else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }

        impClauseService.add(agreement.getId(),impClauseDTO);

        //保存协议报价
        impQuoteService.saveImpQuotes(agreement.getId(),agreement.getCustomerId(),impQuotes);

        //关联文件信息
        uploadFileService.relateFile(agreement.getId().toString(),dto.getFile());

        //生成任务通知
        createNotice(agreement,customer);
        return agreement.getId();
    }

    @Override
    public void editPlus(AgreemenPlusDTO dto) {
        AgreementDTO agreementDTO = dto.getAgreement();
        Agreement agreement = super.getById(agreementDTO.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("协议不存在，请刷新页面重试"));
        //原始单据状态
        AgreementStatusEnum historyStatus = AgreementStatusEnum.of(agreement.getStatusId());
        //验证状态是否可以执行操作
        DomainOprationEnum oprationEnum = DomainOprationEnum.AGREEMENT_EDIT;
        DomainStatus.getInstance().check(oprationEnum, agreement.getStatusId());

        //取原来客户信息更新，修改不能更改客户
        Customer customer = customerService.getById(agreement.getCustomerId());
        agreement.setPartyaName(customer.getName());
        agreement.setPartyaSocialNo(customer.getSocialNo());
        agreement.setPartyaLegalPerson(customer.getLegalPerson());
        agreement.setPartyaTel(customer.getTel());
        agreement.setPartyaFax(customer.getFax());
        agreement.setPartyaAddress(customer.getAddress());
        //获取乙方(主体公司)
        SubjectVO subjectVO = subjectService.findByCode();
        TsfPreconditions.checkArgument(Objects.nonNull(subjectVO),new ServiceException("获取乙方信息失败"));
        agreement.setPartybName(subjectVO.getName());
        agreement.setPartybSocialNo(subjectVO.getSocialNo());
        agreement.setPartybLegalPerson(subjectVO.getLegalPerson());
        agreement.setPartybTel(subjectVO.getTel());
        agreement.setPartybFax(subjectVO.getFax());
        agreement.setPartybAddress(subjectVO.getAddress());

        //赋值其他数据
        agreement.setDocNo(agreementDTO.getDocNo());
        agreement.setBusinessType(agreementDTO.getBusinessType());
        agreement.setDeclareType(agreementDTO.getDeclareType());
        agreement.setSigningDate(agreementDTO.getSigningDate());
        agreement.setEffectDate(agreementDTO.getEffectDate());
        agreement.setInvalidDate(agreementDTO.getInvalidDate());
        agreement.setDelayYear(agreementDTO.getDelayYear());
        //实际失效时间
        agreement.setActualInvalidDate(agreement.getInvalidDate());
        if(agreement.getDelayYear()>0){
            agreement.setActualInvalidDate(agreement.getActualInvalidDate().plusYears(agreement.getDelayYear()));
        }
        agreement.setMainProduct(agreementDTO.getMainProduct());
        agreement.setMemo(agreementDTO.getMemo());
        List<ImpQuoteDTO> impQuotes = dto.getImpQuotes();
        TsfPreconditions.checkArgument(CollUtil.isNotEmpty(impQuotes),new ServiceException("请至少选择一种账期报价"));
        agreement.setQuoteDescribe(impQuoteService.quoteDescribe(beanMapper.mapAsList(impQuotes,ImpQuote.class)));
        AgreementStatusEnum statusEnum = Objects.equals(Boolean.TRUE,dto.getAgreement().getSubmitAudit())?AgreementStatusEnum.WAIT_EXAMINE:AgreementStatusEnum.SAVED;
        agreement.setStatusId(statusEnum.getCode());
        // 协议版本
        agreement.setVersion(agreementVersion);
        //代理进口 - 代理只能双抬头
        BusinessTypeEnum IMP_AGENT = BusinessTypeEnum.IMP_AGENT;
        if(IMP_AGENT == BusinessTypeEnum.of(agreement.getBusinessType())){
            DeclareTypeEnum SINGLE = DeclareTypeEnum.SINGLE;//单抬头
            TsfPreconditions.checkArgument(SINGLE != DeclareTypeEnum.of(agreement.getDeclareType()),new ServiceException(String.format("%s业务不能选择%s报关",IMP_AGENT.getName(),SINGLE.getName())));
        }
        try{
            super.updateById(agreement);
            //记录历史状态
            statusHistoryService.saveHistory(oprationEnum,
                    agreement.getId().toString(),Agreement.class.getName(),
                    historyStatus.getCode(),historyStatus.getName(),
                    statusEnum.getCode(),statusEnum.getName(),
                    Objects.equals(AgreementStatusEnum.SAVED,statusEnum)?"临时保存":"提交审核"
            );
        }catch (DuplicateKeyException e) {
            if(e.getMessage().contains("UK_agreement_doc_no")) {
                throw new ServiceException("协议编号已经存在请修改");
            }else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }

        //修改协议约定
        ImpClauseDTO impClauseDTO = dto.getImpClause();
        impClauseService.edit(agreement.getId(),impClauseDTO);

        //保存协议报价
        impQuoteService.saveImpQuotes(agreement.getId(),agreement.getCustomerId(),impQuotes);

        //生成任务通知
        createNotice(agreement,customer);
    }

    public void createNotice(Agreement agreement,Customer customer) {
        //待审核
        if(Objects.equals(AgreementStatusEnum.WAIT_EXAMINE.getCode(),agreement.getStatusId())) {
            TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
            taskNoticeContentDTO.setDocumentType(DomainTypeEnum.AGREEMENT.getCode());
            taskNoticeContentDTO.setDocumentId(agreement.getId().toString());
            taskNoticeContentDTO.setCustomerId(customer.getId());
            taskNoticeContentDTO.setCustomerName(customer.getName());
            taskNoticeContentDTO.setOperationCode(DomainOprationEnum.AGREEMENT_EXAMINE.getCode());
            taskNoticeContentDTO.setContent(String.format("【%s】提交了一份【%s】进口协议报价单需要您审批。",SecurityUtil.getCurrentPersonName(),customer.getName()));
            taskNoticeContentDTO.setQueryParamsMap(ImmutableMap.of("docNo",agreement.getDocNo()));
            taskNoticeContentService.add(taskNoticeContentDTO);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        Agreement agreement = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("协议不存在，请刷新页面重试"));
        //根据协议删除客户按重计费报价
        customerExpressQuoteService.removeByAgreementId(agreement.getId());
        //根据协议删除报价
        impQuoteService.deleteByAgreementId(id);
        //删除条款
        impClauseService.removeById(id);
        //删除协议
        super.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void examine(TaskDTO dto) {
       commonService.changeDocumentStatus(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void originSignBack(List<Long> ids) {
        List<Agreement> agreementList = agreementMapper.selectByIdsAndIsSignBack(ids,Boolean.FALSE);
        agreementList.stream().forEach(agreement -> {
            //检查是否存在原件附件
            FileQTO qto = new FileQTO();
            qto.setDocId(agreement.getId().toString());
            qto.setDocType("agreement");
            qto.setBusinessType("agr_original");
            Integer count = uploadFileService.count(qto);
            TsfPreconditions.checkArgument(count>0,new ServiceException(String.format("协议【%s】原件附件不存在",agreement.getDocNo())));
            agreement.setIsSignBack(Boolean.TRUE);
            agreement.setSignBackPerson(SecurityUtil.getCurrentPersonName());
            super.updateById(agreement);
        });
    }

    @Override
    public Agreement getEffectiveAgreement(Long customerId,@NonNull BusinessTypeEnum businessTypeEnum) {
        TsfWeekendSqls wheres = TsfWeekendSqls.<Agreement>custom()
                .andEqualTo(false,Agreement::getCustomerId,customerId)//客户
                .andEqualTo(false,Agreement::getStatusId,AgreementStatusEnum.AUDITED.getCode())//已审核
                .andGreaterThan(false,Agreement::getActualInvalidDate,LocalDateTime.now().plusDays(-1))//时间有效期(当前时间带时分秒减掉一天)
                .andEqualTo(false,Agreement::getBusinessType,businessTypeEnum.getCode());//业务类型
        List<Agreement> agreementList = agreementMapper.selectByExample(Example.builder(Agreement.class).where(wheres).build());
        if(CollUtil.isNotEmpty(agreementList)) {
            return agreementList.get(0);
        }
        return null;
    }

    @Override
    public List<ImpAgreementVO> impAgreement(Long customerId) {
        List<ImpAgreementVO> agreementVOList = Lists.newArrayList();
        TsfWeekendSqls wheres = TsfWeekendSqls.<Agreement>custom()
                .andEqualTo(false,Agreement::getCustomerId,customerId)//客户
                .andEqualTo(false,Agreement::getStatusId,AgreementStatusEnum.AUDITED.getCode())//已审核
                .andGreaterThan(false,Agreement::getActualInvalidDate,LocalDateTime.now().plusDays(-1));//时间有效期(当前时间带时分秒减掉一天)
        List<Agreement> agreementList = agreementMapper.selectByExample(Example.builder(Agreement.class).where(wheres).build());
        if(CollUtil.isNotEmpty(agreementList)){
            agreementList = agreementList.stream().sorted(Comparator.comparing(Agreement::getDateCreated).reversed()).collect(Collectors.toList());
            agreementList.stream().forEach(agreement -> {
                ImpAgreementVO vo = new ImpAgreementVO();
                vo.setBusinessType(agreement.getBusinessType());//业务类型
                vo.setDeclareType(agreement.getDeclareType());//报关类型
                ImpClause impClause = impClauseService.findByAgreementId(agreement.getId());
                vo.setTransactionMode(impClause.getTransactionMode());//成交方式
                //获取报价
                List<ImpQuote> impQuoteList = impQuoteService.findByAgreementId(agreement.getId());
                List<SimpleQuoteVO> quoteVOS = Lists.newArrayList();
                impQuoteList.stream().forEach(impQuote -> {
                    SimpleQuoteVO simpleQuoteVO = new SimpleQuoteVO();
                    simpleQuoteVO.setId(impQuote.getId());
                    simpleQuoteVO.setMemo(impQuoteService.quoteDescribe(impQuote));
                    quoteVOS.add(simpleQuoteVO);
                });
                vo.setQuotes(quoteVOS);
                agreementVOList.add(vo);
            });
        }
        return agreementVOList;
    }

    @Override
    public List<ImpAgreementVO> impAgreementCheck(Long customerId) {
        List<ImpAgreementVO> impAgreementVOS = impAgreement(customerId);
        if(CollUtil.isEmpty(impAgreementVOS)){
            throw new ServiceException("未找到当前客户有效的协议报价");
        }
        return impAgreementVOS;
    }

    @Override
    public List<ImpAgreementVO> clientImpAgreementCheck() {
        Long customerId = SecurityUtil.getCurrentCustomerId();
        //根据客户查询有效的供应链框架协议
        //手机端提示前往电脑端签署
        Boolean isMobile = IpUtils.isMobile(request);
        List<ImpAgreementVO> impAgreementVOS = impAgreement(customerId);
        if(CollUtil.isEmpty(impAgreementVOS)){
            if(isMobile) {
                throw new ServiceException("对不起，未找到您有效的协议报价，请立即前往电脑端签署。");
            } else {
                throw new ServiceException("对不起，未找到您有效的协议报价，请立即前往签署。");
            }
        }
        return impAgreementVOS;
    }

    @Override
    public Agreement validationAgreement(Long id) {
        TsfWeekendSqls wheres = TsfWeekendSqls.<Agreement>custom()
                .andEqualTo(false,Agreement::getId,id)//ID
                .andEqualTo(false,Agreement::getStatusId,AgreementStatusEnum.AUDITED.getCode())//已审核
                .andGreaterThan(false,Agreement::getActualInvalidDate,LocalDateTime.now().plusDays(-1));//时间有效期(当前时间带时分秒减掉一天)
        return agreementMapper.selectOneByExample(Example.builder(Agreement.class).where(wheres).build());
    }

    @Override
    public Agreement obtainCustomerNewEffective(Long customerId) {
        return agreementMapper.obtainCustomerNewEffective(customerId);
    }

    @Override
    public List<ClientImpQuotePlusVO> initSign(Long customerId) {
        List<ClientImpQuotePlusVO> quoteList = Lists.newArrayList();
        Long fileId = null;
        // 查询客户是否存在待确认的报价单
        Agreement agreement = agreementMapper.findOneByCustomerIdAndStatusId(customerId,AgreementStatusEnum.WAIT_CONFIRM.getCode());
        if(Objects.isNull(agreement)){
            // 查询客户是否存在已确认的报价单
            agreement = agreementMapper.findOneByCustomerIdAndStatusId(customerId,AgreementStatusEnum.AUDITED.getCode());
            if(Objects.nonNull(agreement)){
                fileId = agreement.getQfileId();
            }
        }
        if(Objects.isNull(agreement)){
            // 初始化新的协议报价
            ClientImpQuotePlusVO ciq = new ClientImpQuotePlusVO();
            ImpQuote impQuote = impQuoteService.initBaseQuote();
            ciq.setQuoteType(impQuote.getQuoteType());// 预付款
            ciq.setAgreeMode(impQuote.getAgreeMode());//进口日
            ciq.setDay(impQuote.getDay());
            ciq.setTaxIncluded(impQuote.getTaxIncluded());//加税点
            ciq.setAgencyFeeMode(impQuote.getAgencyFeeMode());//按重量计费
            List<ExpressStandardQuoteMemberVO> expressStandardQuoteMemberVOList = expressStandardQuoteService.getCurrentEffective(ciq.getQuoteType());
            if(CollUtil.isEmpty(expressStandardQuoteMemberVOList)){
                throw new ServiceException(String.format("业务类型【%s】按重计费模式未找到标准报价",ciq.getQuoteTypeDesc()));
            }
            ciq.setExpressQuoteList(expressStandardQuoteMemberVOList);
            quoteList.add(ciq);
        }else{
            //查询报价单明细
            List<ImpQuote> impQuotes = impQuoteService.findByAgreementId(agreement.getId());
            for(ImpQuote iq : impQuotes){
                ClientImpQuotePlusVO ciq = beanMapper.map(iq,ClientImpQuotePlusVO.class);
                ciq.setAgreementStatus(agreement.getStatusId());
                ciq.setAgreementBusinessType(agreement.getBusinessType());
                // 按重计费查询标准报价
                if(Objects.equals(AgencyFeeModeEnum.EXPRESS,AgencyFeeModeEnum.of(ciq.getAgencyFeeMode()))){
                    List<ExpressStandardQuoteMemberVO> expressStandardQuoteMemberVOList = expressStandardQuoteService.getCurrentEffective(ciq.getQuoteType());
                    if(CollUtil.isEmpty(expressStandardQuoteMemberVOList)){
                        throw new ServiceException(String.format("业务类型【%s】按重计费模式未找到标准报价",ciq.getQuoteTypeDesc()));
                    }
                    ciq.setExpressQuoteList(expressStandardQuoteMemberVOList);
                }
                ciq.setFileId(fileId);
                quoteList.add(ciq);
            }
        }
        return quoteList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agreeSignAgreement(ServiceAgreementVO serviceAgreementVO,BusinessTypeEnum businessTypeEnum, List<ClientImpQuotePlusVO> clientImpQuotePlusVOS) {
        if(Objects.isNull(serviceAgreementVO.getId())){
            throw new ServiceException("对不起，进口供应链报价协议有变更请刷新页面重新签署");
        }
        Agreement agreement = super.getById(serviceAgreementVO.getId());
        if(Objects.isNull(agreement)){
            throw new ServiceException("对不起，进口供应链报价协议有变更请刷新页面重新签署");
        }
        AgreementStatusEnum statusEnum = AgreementStatusEnum.of(agreement.getStatusId());
        if(Objects.equals(statusEnum,AgreementStatusEnum.WAIT_CONFIRM)){
            //确认报价单
            agreement.setPartyaLinkPerson(serviceAgreementVO.getPartyaLinkPerson());
            agreement.setPartyaMail(serviceAgreementVO.getPartyaMail());
            agreement.setPartyaAccountNo(serviceAgreementVO.getPartyaAccountNo());
            confirmAgreement(agreement);
        }else{
            throw new ServiceException("对不起，进口供应链报价协议有变更请刷新页面重新签署");
        }
    }


    // 生成报价PDF
    @Transactional(rollbackFor = Exception.class)
    public UploadFile createImpQuotePdf(Agreement agreement,List<ImpQuote> quoteList){
        UploadFile uploadFile = new UploadFile();
        uploadFile.setDocId(agreement.getId().toString());
        uploadFile.setDocType("agreement_quote");
        uploadFile.setBusinessType("agreement_quote_pdf");
        uploadFile.setMemo("协议报价原始PDF");
        FileOutputStream fos = null;
        Document document = null;
        try{
            //文件存放路径
            String path = fileDirectory + String.format("%s/%s/%s/", uploadFile.getDocType(), uploadFile.getBusinessType(),agreement.getCustomerId());
            //文件存放名称
            String sysFileName = agreement.getDocNo().concat(".pdf");
            //创建文件存放目录
            File dirFile = new File(path);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            fos = new FileOutputStream(new File(path.concat(sysFileName)));
            // 字体宋体
            BaseFont stfont = BaseFont.createFont("/font/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            //标题字体
            Font titleFont = new Font(stfont, Float.valueOf("10.45"), Font.NORMAL, BaseColor.BLACK);
            //标题字体(加粗)
            Font titleBoldFont = new Font(stfont, Float.valueOf("15.45"), Font.BOLD, BaseColor.BLACK);
            //正文字体
            Font textFont = new Font(stfont, Float.valueOf("10.45"), Font.NORMAL, BaseColor.BLACK);
            //正文字体(加粗)
            Font textBoldFont = new Font(stfont, Float.valueOf("10.45"), Font.BOLD, BaseColor.BLACK);
            document = new Document();
            PdfWriter.getInstance(document, fos);
            document.open();
            Paragraph content = new Paragraph("附件2",titleBoldFont);
            content.setAlignment(Element.ALIGN_CENTER);// 居中
            document.add(content);
            document.add(new Paragraph(" ",textFont));//空行
            content = new Paragraph("补充协议",titleBoldFont);
            content.setAlignment(Element.ALIGN_CENTER);// 居中
            document.add(content);
            document.add(new Paragraph(" ",textFont));//空行
            PdfPTable table = new PdfPTable(4);
            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            table.getDefaultCell().setFixedHeight(18);
            table.setWidthPercentage(100);
            table.setWidths(new int[]{13, 35, 17, 35});
            PdfPCell cell = new PdfPCell(new Phrase("甲方：",textFont));
            cell.setBorder(0);
            table.addCell(cell);
            LineSeparator line = new LineSeparator(0.5f,100,BaseColor.BLACK,Element.ALIGN_CENTER,-2f);
            Phrase phrase = new Phrase(agreement.getPartyaName(),textFont);
            phrase.add(line);
            table.addCell(phrase);
            table.addCell(new Phrase("统一社会信用代码：",textFont));
            phrase = new Phrase(agreement.getPartyaSocialNo(),textFont);
            phrase.add(line);
            table.addCell(phrase);
            cell = new PdfPCell(new Phrase("注册地址：",textFont));
            cell.setBorder(0);
            table.addCell(cell);
            phrase = new Phrase(agreement.getPartyaAddress(),textFont);
            phrase.add(line);
            cell = new PdfPCell(phrase);
            cell.setBorder(0);
            cell.setColspan(3);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("乙方：",textFont));
            cell.setBorder(0);
            table.addCell(cell);
            phrase = new Phrase(agreement.getPartybName(),textFont);
            phrase.add(line);
            table.addCell(phrase);
            table.addCell(new Phrase("统一社会信用代码：",textFont));
            phrase = new Phrase(agreement.getPartybSocialNo(),textFont);
            phrase.add(line);
            table.addCell(phrase);
            cell = new PdfPCell(new Phrase("联系地址：",textFont));
            cell.setFixedHeight(18);
            cell.setBorder(0);
            table.addCell(cell);
            phrase = new Phrase(agreement.getPartybAddress(),textFont);
            phrase.add(line);
            cell = new PdfPCell(phrase);
            cell.setBorder(0);
            cell.setColspan(3);
            table.addCell(cell);
            document.add(table);

            document.add(new Paragraph("基于甲乙双方在签署《供应链服务协议》基础上，双方友好协商约定税票类型和服务收费达成如下报价单：",textFont));
            document.add(new Paragraph(" ",textFont));//空行

            table = new PdfPTable(2);
            table.getDefaultCell().setBorder(PdfPCell.BOX);
            table.getDefaultCell().setFixedHeight(16);
            table.setWidthPercentage(100);
            table.setWidths(new int[]{10, 90});
            table.addCell(new Phrase("税单类型",textFont));
            table.addCell(new Phrase(Objects.equals(BusinessTypeEnum.IMP_AGENT,BusinessTypeEnum.of(agreement.getBusinessType()))?"√ 服务类增值税专用发票（双抬头）":"√ 销售货物类增值税专用发票（单抬头）",textBoldFont));
            document.add(table);
            document.add(new Paragraph(" ",textFont));//空行

            for(ImpQuote quote : quoteList){
                table = new PdfPTable(4);
                table.getDefaultCell().setBorder(PdfPCell.BOX);
                table.getDefaultCell().setFixedHeight(16);
                table.setWidthPercentage(100);
                table.setWidths(new int[]{10,40,10,40});
                table.addCell(new Phrase("业务类型",textFont));
                table.addCell(new Phrase(QuoteTypeEnum.of(quote.getQuoteType()).getName(),textBoldFont));
                table.addCell(new Phrase("计费模式",textFont));
                table.addCell(new Phrase(AgencyFeeModeEnum.of(quote.getAgencyFeeMode()).getName(),textBoldFont));
                document.add(table);
                table = new PdfPTable(2);
                table.getDefaultCell().setBorder(PdfPCell.BOX);
                table.getDefaultCell().setFixedHeight(16);
                table.setWidthPercentage(100);
                table.setWidths(new int[]{10,90});
                table.addCell(new Phrase("服务费",textFont));
                StringBuffer sb = new StringBuffer("");
                if(quote.getBasePrice().compareTo(BigDecimal.ZERO) == 1){
                    sb.append(StringUtils.formatCurrency(quote.getBasePrice()));
                    sb.append("RMB/单 + ");
                }
                sb.append("（报关金额 * 海关汇率 ");
                if(Objects.equals(TaxTypeEnum.AFTER_TAX,TaxTypeEnum.of(quote.getTaxType()))){
                    sb.append("+ 税款");
                }
                sb.append(") * ");
                sb.append(quote.getServiceRate());
                sb.append("%");
                if(quote.getMinCost().compareTo(BigDecimal.ZERO) == 1){
                    sb.append(" 最低消费:");
                    sb.append(StringUtils.formatCurrency(quote.getMinCost()));
                    sb.append("RMB");
                }
                table.addCell(new Phrase(sb.toString(),textFont));
                document.add(table);
                //预付款业务
                if(Objects.equals(QuoteTypeEnum.ADVANCE_CHARGE,QuoteTypeEnum.of(quote.getQuoteType()))){
                    table = new PdfPTable(2);
                    table.getDefaultCell().setBorder(PdfPCell.BOX);
                    table.getDefaultCell().setFixedHeight(16);
                    table.setWidthPercentage(100);
                    table.setWidths(new int[]{10,90});
                    table.addCell(new Phrase("付款期限及方式",textFont));
                    cell = new PdfPCell(new Phrase("甲方需在乙方进口申报前将服务费及预估的进口关税、增值税、物流杂费、运保费等各项费用总额以网银转账的方式支付人民币给乙方，实际费用以进口后确定的金额为准，差额部分需进口后7个自然日内结清，未收到甲方上述费用前乙方有权拒绝服务。",textFont));
                    cell.setFixedHeight(34);
                    table.addCell(cell);
                    document.add(table);
                }else{
                    //垫款业务
                    table = new PdfPTable(2);
                    table.getDefaultCell().setBorder(PdfPCell.BOX);
                    table.getDefaultCell().setFixedHeight(16);
                    table.setWidthPercentage(100);
                    table.setWidths(new int[]{10,90});
                    table.addCell(new Phrase("付款期限及方式",textFont));
                    sb = new StringBuffer("1、服务费、物流杂费等各项杂费支付日期进口申报");
                    float rowHeight = 50;
                    if(Objects.equals(AgreeModeEnum.IMPORT_DAY,AgreeModeEnum.of(quote.getAgreeMode()))){
                        if(quote.getDay()>0){
                            sb.append("后");
                            sb.append(quote.getDay());
                            sb.append("天内");
                        }else{
                            sb.append("前");
                        }
                    }else if(Objects.equals(AgreeModeEnum.MONTH,AgreeModeEnum.of(quote.getAgreeMode()))){
                        if(quote.getMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getMonthDay());
                        sb.append("号前");
                    }else if(Objects.equals(AgreeModeEnum.HALF_MONTH,AgreeModeEnum.of(quote.getAgreeMode()))){
                        sb.append("1号到15号");
                        if(quote.getFirstMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getFirstMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getFirstMonthDay());
                        sb.append("号前 16号到月末");
                        if(quote.getLowerMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getLowerMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getLowerMonthDay());
                        sb.append("号前");
                    }else if(Objects.equals(AgreeModeEnum.WEEK,AgreeModeEnum.of(quote.getAgreeMode()))){
                        if(quote.getWeek() <= 0){
                            sb.append("当周");
                        }else{
                            sb.append("第");
                            sb.append(quote.getWeek());
                            sb.append("周");
                        }
                        sb.append("星期");
                        sb.append(quote.getWeekDay());
                        sb.append("前");
                    }
                    sb.append("\r\n2、关税、增值税等各项税费支付日期进口申报");
                    if(Objects.equals(AgreeModeEnum.IMPORT_DAY,AgreeModeEnum.of(quote.getTaxAgreeMode()))){
                        if(quote.getTaxDay()>0){
                            sb.append("后");
                            sb.append(quote.getTaxDay());
                            sb.append("天内");
                        }else{
                            sb.append("前");
                        }
                    }else if(Objects.equals(AgreeModeEnum.MONTH,AgreeModeEnum.of(quote.getTaxAgreeMode()))){
                        if(quote.getTaxMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getTaxMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getTaxMonthDay());
                        sb.append("号前");
                    }else if(Objects.equals(AgreeModeEnum.HALF_MONTH,AgreeModeEnum.of(quote.getTaxAgreeMode()))){
                        sb.append("1号到15号");
                        if(quote.getTaxFirstMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getTaxFirstMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getTaxFirstMonthDay());
                        sb.append("号前 16号到月末");
                        if(quote.getTaxLowerMonth()<=0){
                            sb.append("当月");
                        }else{
                            sb.append("第");
                            sb.append(quote.getTaxLowerMonth());
                            sb.append("个月");
                        }
                        sb.append(quote.getTaxLowerMonthDay());
                        sb.append("号前");
                    }else if(Objects.equals(AgreeModeEnum.WEEK,AgreeModeEnum.of(quote.getTaxAgreeMode()))){
                        if(quote.getTaxWeek() <= 0){
                            sb.append("当周");
                        }else{
                            sb.append("第");
                            sb.append(quote.getTaxWeek());
                            sb.append("周");
                        }
                        sb.append("星期");
                        sb.append(quote.getTaxWeekDay());
                        sb.append("前");
                    }
                    if(Objects.equals(QuoteTypeEnum.PAD_GOOD,QuoteTypeEnum.of(quote.getQuoteType()))){
                        rowHeight = 60;
                        sb.append("\r\n3、货款支付日期申请付汇");
                        if(Objects.equals(AgreeModeEnum.PAYMENT_DAY,AgreeModeEnum.of(quote.getGoAgreeMode()))){
                            if(quote.getGoDay()>0){
                                sb.append("后");
                                sb.append(quote.getGoDay());
                                sb.append("天内");
                            }else{
                                sb.append("前");
                            }
                        }else if(Objects.equals(AgreeModeEnum.MONTH,AgreeModeEnum.of(quote.getGoAgreeMode()))){
                            if(quote.getGoMonth()<=0){
                                sb.append("当月");
                            }else{
                                sb.append("第");
                                sb.append(quote.getGoMonth());
                                sb.append("个月");
                            }
                            sb.append(quote.getGoMonthDay());
                            sb.append("号前");
                        }else if(Objects.equals(AgreeModeEnum.HALF_MONTH,AgreeModeEnum.of(quote.getGoAgreeMode()))){
                            sb.append("1号到15号");
                            if(quote.getGoFirstMonth()<=0){
                                sb.append("当月");
                            }else{
                                sb.append("第");
                                sb.append(quote.getGoFirstMonth());
                                sb.append("个月");
                            }
                            sb.append(quote.getGoFirstMonthDay());
                            sb.append("号前 16号到月末");
                            if(quote.getGoLowerMonth()<=0){
                                sb.append("当月");
                            }else{
                                sb.append("第");
                                sb.append(quote.getGoLowerMonth());
                                sb.append("个月");
                            }
                            sb.append(quote.getGoLowerMonthDay());
                            sb.append("号前");
                        }else if(Objects.equals(AgreeModeEnum.WEEK,AgreeModeEnum.of(quote.getGoAgreeMode()))){
                            if(quote.getGoWeek() <= 0){
                                sb.append("当周");
                            }else{
                                sb.append("第");
                                sb.append(quote.getGoWeek());
                                sb.append("周");
                            }
                            sb.append("星期");
                            sb.append(quote.getGoWeekDay());
                            sb.append("前");
                        }
                    }
                    sb.append("\r\n   请将以上费用总额按照账期约定以网银转账的方式支付人民币给乙方，实际费用以进口后确定的金额为准");
                    if(quote.getOverdueRate().compareTo(BigDecimal.ZERO) == 1){
                        sb.append("，如未按账期支付则甲方将需支付逾期金额/");
                        sb.append(quote.getOverdueRate());
                        sb.append("%天滞纳金给乙方");
                    }
                    sb.append("，未收到甲方上述费用前乙方有权拒绝服务。");
                    cell = new PdfPCell(new Phrase(sb.toString(),textFont));
                    cell.setFixedHeight(rowHeight);
                    table.addCell(cell);
                    document.add(table);
                }
            }
            document.add(new Paragraph(" ",textFont));//空行

//            document.add(new Paragraph(" ",textFont));//空行
//            table = new PdfPTable(4);
//            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
//            table.getDefaultCell().setFixedHeight(22);
//            table.setWidthPercentage(100);
//            table.setWidths(new int[]{15, 35, 15, 35});
//            table.addCell(new Phrase("甲方：",textFont));
//            table.addCell(new Phrase(agreement.getPartyaName(),textFont));
//            table.addCell(new Phrase("乙方：",textFont));
//            table.addCell(new Phrase(agreement.getPartybName(),textFont));
//            table.addCell(new Phrase("授权代表人：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            table.addCell(new Phrase("授权代表人：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            table.addCell(new Phrase("签章：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            table.addCell(new Phrase("签章：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            table.addCell(new Phrase("日期：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            table.addCell(new Phrase("日期：",textFont));
//            table.addCell(new Phrase(" ",textFont));
//            document.add(table);

            uploadFile.setName(sysFileName);
            uploadFile.setNname(sysFileName);
            uploadFile.setPath(path);
            uploadFile.setUid("-1");
            uploadFile.setUname("系统");
            uploadFile.setExtension("pdf");
            uploadFile.setIsDelete(Boolean.FALSE);
            uploadFile.setCreateBy(uploadFile.getUid().concat("/").concat(uploadFile.getUname()));
            uploadFile.setDateCreated(LocalDateTime.now());
            uploadFile.setUpdateBy(uploadFile.getCreateBy());
            uploadFile.setDateUpdated(uploadFile.getDateCreated());
            uploadFileService.save(uploadFile);
        }catch (Exception e){
            log.error("生成协议报价单PDF失败：",e);
            throw new ServiceException("生成协议报价单PDF失败");
        }finally {
            if(Objects.nonNull(document)){
                document.close();
            }
            IOUtils.closeQuietly(fos);
        }
        return uploadFile;
    }
    // 生成服务协议PDF
    @Transactional(rollbackFor = Exception.class)
    public UploadFile createImpServiceAgreementPdf(Agreement agreement,ImpClause impClause){
        ClassPathResource resource = new ClassPathResource("pdf/tpl_service_greement.pdf");
        UploadFile uploadFile = new UploadFile();
        uploadFile.setDocId(agreement.getId().toString());
        uploadFile.setDocType("service_greement");
        uploadFile.setBusinessType("service_greement_pdf");
        uploadFile.setMemo("框架协议系统原始PDF");
        FileOutputStream fos = null;
        ByteArrayOutputStream bos = null;
        PdfReader reader = null;
        try{
            reader = new PdfReader(resource.getInputStream());
            bos = new ByteArrayOutputStream();
            PdfStamper ps = new PdfStamper(reader, bos);
            AcroFields s = ps.getAcroFields();
            s.setField("docNo", agreement.getDocNo());
            s.setField("partyaName", agreement.getPartyaName());
            s.setField("partyaSocialNo", agreement.getPartyaSocialNo());
            s.setField("partyaAddress", agreement.getPartyaAddress());
            s.setField("partyaLegalPerson", agreement.getPartyaLegalPerson());
            s.setField("partyaTel", agreement.getPartyaTel());
            s.setField("partyaFax", agreement.getPartyaFax());
            s.setField("partybName", agreement.getPartybName());
            s.setField("partybSocialNo", agreement.getPartybSocialNo());
            s.setField("partybAddress", agreement.getPartybAddress());
            s.setField("partybLegalPerson", agreement.getPartybLegalPerson());
            s.setField("partybMail", agreement.getPartybName());
            s.setField("partybTel", agreement.getPartybTel());
            s.setField("partybFax", agreement.getPartybFax());
            s.setField("version", agreement.getVersion());
            s.setField("signingDate", LocalDateTimeUtils.formatTime(agreement.getSigningDate(),"yyyy年MM月dd日"));
            s.setField("effectDate", LocalDateTimeUtils.formatTime(agreement.getEffectDate(),"yyyy年MM月dd日"));
            s.setField("invalidDate", LocalDateTimeUtils.formatTime(agreement.getInvalidDate(),"yyyy年MM月dd日"));
            s.setField("delayYear", agreement.getDelayYear().toString());
            s.setField("mainProduct", agreement.getMainProduct());
            s.setField("overdueDays", impClause.getOverdueDays().toString());
            // 账号
            s.setField("partyaAccountNo", agreement.getPartyaAccountNo());
            // 授权联系人
            s.setField("partyaLinkPerson", agreement.getPartyaLinkPerson());
            // 邮箱
            s.setField("partyaMail", agreement.getPartyaMail());
            // 注册地址
            s.setField("partybRegAddress", agreement.getPartybAddress());

            if("pay_bank_china_sell".equals(impClause.getGoodsRate())){
                if("now".equals(impClause.getGoodsRate())){
                    s.setField("goodsRateTime", "乙方付汇当日中国银行提交申请时第一个相应外汇卖出价");
                }else{
                    s.setField("goodsRateTime", "乙方付汇当日中国银行"+impClause.getGoodsRateTime()+"第一个相应外汇卖出价");
                }
            }
            ps.setFormFlattening(true);
            ps.close();
            //文件存放路径
            String path = fileDirectory + String.format("%s/%s/%s/", uploadFile.getDocType(), uploadFile.getBusinessType(),agreement.getCustomerId());
            //文件存放名称
            String sysFileName = agreement.getDocNo()+"_framework_agreement.pdf";
            //创建文件存放目录
            File dirFile = new File(path);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            fos = new FileOutputStream(new File(path.concat(sysFileName)));
            fos.write(bos.toByteArray());

            // 报价单文件
            String quotePdf = fileDirectory + String.format("%s/%s/%s/%s.pdf", "agreement_quote", "agreement_quote_pdf",agreement.getCustomerId(),agreement.getDocNo());
            // 合并PDF
            PDFMergerUtility mergePdf = new PDFMergerUtility();
            mergePdf.addSource(path.concat(sysFileName));
            mergePdf.addSource(fileDirectory+"temp/tpl_service_greement1.pdf");
            mergePdf.addSource(quotePdf);
            mergePdf.addSource(fileDirectory+"temp/tpl_service_greement2.pdf");
            mergePdf.setDestinationFileName(path + agreement.getDocNo()+".pdf");
            mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());

            uploadFile.setName(agreement.getDocNo()+".pdf");
            uploadFile.setNname(agreement.getDocNo()+".pdf");
            uploadFile.setPath(path);
            uploadFile.setUid("-1");
            uploadFile.setUname("系统");
            uploadFile.setExtension("pdf");
            uploadFile.setIsDelete(Boolean.FALSE);
            uploadFile.setCreateBy(uploadFile.getUid().concat("/").concat(uploadFile.getUname()));
            uploadFile.setDateCreated(LocalDateTime.now());
            uploadFile.setUpdateBy(uploadFile.getCreateBy());
            uploadFile.setDateUpdated(uploadFile.getDateCreated());
            uploadFileService.save(uploadFile);
        }catch (Exception e){
            log.error("生成服务协议PDF失败：",e);
            throw new ServiceException("生成服务协议PDF失败");
        }finally {
            IOUtils.closeQuietly(fos);
            IOUtils.closeQuietly(bos);
            if(Objects.nonNull(reader)){
                reader.close();
            }
        }
        return uploadFile;
    }

    public String generateDocNo(){
        return serialNumberService.generateDocNo(SerialNumberTypeEnum.IMP_QUOTE);
    }

    @Transactional(rollbackFor = Exception.class)
    public void confirmAgreement(Agreement agreement){
        AgreementStatusEnum statusEnum = AgreementStatusEnum.AUDITED;//状态已确认
        agreement.setStatusId(statusEnum.getCode());//状态
        super.updateById(agreement);
        //记录历史状态
        statusHistoryService.saveHistory(DomainOprationEnum.AREEMENT_ADD,
                agreement.getId().toString(),Agreement.class.getName(),
                statusEnum.getCode(),statusEnum.getName(),"确定签约");
        List<ImpQuote> impQuoteList = impQuoteService.findByAgreementId(agreement.getId());
        impQuoteList.stream().forEach(impQuote ->{
            List<ExpressStandardQuoteMemberVO> expressStandardQuoteMemberVOList = expressStandardQuoteService.getCurrentEffective(impQuote.getQuoteType());
            CustomerExpressQuote customerExpressQuote = customerExpressQuoteService.saveByBaseExpressQuote(agreement.getCustomerId(),impQuote.getQuoteType(),expressStandardQuoteMemberVOList);
            impQuote.setCustomerExpressQuoteId(customerExpressQuote.getId());
            impQuoteService.updateById(impQuote);
        });

        //将其它生效协议置为 作废
        TsfWeekendSqls wheres = TsfWeekendSqls.<Agreement>custom()
                .andEqualTo(false,Agreement::getCustomerId,agreement.getCustomerId())//客户
                .andEqualTo(false,Agreement::getStatusId,AgreementStatusEnum.AUDITED.getCode())//已审核
                .andNotEqualTo(false,Agreement::getId,agreement.getId());//排除自己
        List<Agreement> agreementList = agreementMapper.selectByExample(Example.builder(Agreement.class).where(wheres).build());
        AgreementStatusEnum nowStatusEnum = AgreementStatusEnum.INVALID;
        DomainOprationEnum oprationEnum = DomainOprationEnum.AGREEMENT_SIGN;
        agreementList.stream().forEach(arg -> {
            //原始单据状态
            AgreementStatusEnum historyStatus = AgreementStatusEnum.of(arg.getStatusId());
            arg.setStatusId(nowStatusEnum.getCode());
            super.updateById(arg);
            //记录历史状态
            statusHistoryService.saveHistory(oprationEnum,
                    arg.getId().toString(),Agreement.class.getName(),
                    historyStatus.getCode(),historyStatus.getName(),
                    nowStatusEnum.getCode(),nowStatusEnum.getName(),
                    String.format("新协议[%s]生效，作废此协议",agreement.getDocNo()));
        });

        //写入客户额度
        Customer customer = customerService.getById(agreement.getCustomerId());
        ImpClause impClause = impClauseService.getById(agreement.getId());
        customer.setGoodsQuota(impClause.getGoodsQuota());
        customer.setTaxQuota(impClause.getTaxQuota());
        if(Objects.isNull(customer.getSignDate())){
            customer.setSignDate(LocalDateTimeUtils.convertLocalDate());
        }
        customerService.updateById(customer);

        // 生成报价PDF
        UploadFile uploadFile = createImpQuotePdf(agreement,impQuoteList);
        agreement.setQfileId(uploadFile.getId());

        // 生成服务协议PDF
        uploadFile = createImpServiceAgreementPdf(agreement,impClause);
        agreement.setAfileId(uploadFile.getId());

        super.updateById(agreement);
    }

    @Override
    public Boolean existSignContract() {
        Agreement agreement = agreementMapper.findOneByCustomerIdAndStatusId(SecurityUtil.getCurrentCustomerId(),AgreementStatusEnum.WAIT_CONFIRM.getCode());
        return Objects.nonNull(agreement);
    }

    @Override
    public ServiceAgreementQuotePlusVo clientLoad() {
        LoginVO loginVO = SecurityUtil.getCurrent();
        Customer customer = customerService.getById(loginVO.getCustomerId());
        if(!Objects.equals(CustomerStatusEnum.TYPE_2,CustomerStatusEnum.of(customer.getStatusId()))){
            throw new ServiceException("对不起您的公司资料还未审核通过，无法签署供应链服务协议");
        }
        ServiceAgreementVO agreementVO = null;
        // 查询客户是否存在待确认的协议报价
        Agreement agreement = agreementMapper.findOneByCustomerIdAndStatusId(customer.getId(),AgreementStatusEnum.WAIT_CONFIRM.getCode());
        if(Objects.isNull(agreement)){
            // 查询客户是否存在有效的协议报价
            agreement = agreementMapper.findOneByCustomerIdAndStatusId(customer.getId(),AgreementStatusEnum.AUDITED.getCode());
        }
        if(Objects.nonNull(agreement)){
            agreementVO = beanMapper.map(agreement,ServiceAgreementVO.class);

            ImpClause clause = impClauseService.findByAgreementId(agreement.getId());
            if(Objects.nonNull(clause)){
                agreementVO.setGoodsRate(clause.getGoodsRate());
                agreementVO.setGoodsRateTime(clause.getGoodsRateTime());
                agreementVO.setOverdueDays(clause.getOverdueDays());
            }
            agreementVO.setFileId(agreement.getAfileId());
            // 协议待确认
            if(agreement.getStatusId().equals(AgreementStatusEnum.WAIT_CONFIRM.getCode())){
                agreementVO.setPartyaAccountNo(loginVO.getPhone());
                agreementVO.setPartyaMail(loginVO.getEmail());
                if(!loginVO.getPersonName().startsWith("新用户")){
                    agreementVO.setPartyaLinkPerson(loginVO.getPersonName());
                }

            }
        }else{
            agreementVO = new ServiceAgreementVO();
            agreementVO.setDocNo("");
            agreementVO.setCustomerId(customer.getId());
            agreementVO.setVersion(agreementVersion);
            agreementVO.setPartyaName(customer.getName());
            agreementVO.setPartyaSocialNo(customer.getSocialNo());
            agreementVO.setPartyaLegalPerson(customer.getLegalPerson());
            agreementVO.setPartyaSocialNo(customer.getSocialNo());
            agreementVO.setPartyaAddress(customer.getAddress());
            agreementVO.setPartyaTel(loginVO.getPhone());

            // 获取乙方信息
            SubjectVO subjectVO = subjectService.findByCode();
            agreementVO.setPartybName(subjectVO.getName());
            agreementVO.setPartybSocialNo(subjectVO.getSocialNo());
            agreementVO.setPartybLegalPerson(subjectVO.getLegalPerson());
            agreementVO.setPartybSocialNo(subjectVO.getSocialNo());
            agreementVO.setPartybAddress(subjectVO.getAddress());
            agreementVO.setPartybTel(subjectVO.getTel());
            agreementVO.setPartybFax(subjectVO.getFax());
        }

        // 初始化报价单
        List<ClientImpQuotePlusVO> impQuoteVOS = initSign(customer.getId());
        if(CollUtil.isEmpty(impQuoteVOS)){
            throw new ServiceException("未找到有效报价，请联系我司人员");
        }
        ServiceAgreementQuotePlusVo sqvo = new ServiceAgreementQuotePlusVo();
        sqvo.setAgreement(agreementVO);
        sqvo.setQuoteList(impQuoteVOS);
        return sqvo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agreeSign(ClientServiceAgreementSignDTO dto) {
        ServiceAgreementQuotePlusVo sqpvo = clientLoad();
        //获取框架协议
        ServiceAgreementVO serviceAgreementVO = sqpvo.getAgreement();
        List<ClientImpQuotePlusVO> clientImpQuotePlusVOS = sqpvo.getQuoteList();
        if(!Objects.equals(dto.getId(),serviceAgreementVO.getId())){
            throw new ServiceException("对不起，进口供应链报价协议有变更请刷新页面重新签署");
        }
        String lockKey = DistributedLockEnum.SERVICE_AGREEMENT_SIGN.getCode() + ":"  + SecurityUtil.getCurrentCustomerId();
        Lock lock = redisLockRegistry.obtain(lockKey);
        boolean isLock;
        try {
            isLock = lock.tryLock(lockTime, TimeUnit.SECONDS);
            if (!isLock) {
                log.error(String.format("客户签署协议未获取到锁，客户id：【%s】，操作人：【{}】", SecurityUtil.getCurrentCustomerId()), SecurityUtil.getCurrentPersonName());
                throw new ServiceException("您的协议正在处理中，请勿重复签署");
            }
            serviceAgreementVO.setPartyaLinkPerson(dto.getPartyaLinkPerson());
            serviceAgreementVO.setPartyaMail(dto.getPartyaMail());
            serviceAgreementVO.setPartyaAccountNo(SecurityUtil.getCurrent().getPhone());
            // 保存报价
            agreeSignAgreement(serviceAgreementVO,BusinessTypeEnum.of(serviceAgreementVO.getBusinessType()),clientImpQuotePlusVOS);
        } catch (InterruptedException e) {
            log.error("客户签署协议获取锁异常",e);
            throw new ServiceException("服务拥挤，请稍后再试");
        } finally {
            lock.unlock();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void substituteCustomerSign(SubstituteAgreementDTO dto) {
        Long agreementId = dto.getAgreementId();
        Agreement agreement = super.getById(agreementId);
        Optional.ofNullable(agreement).orElseThrow(()->new ServiceException("进口报价不存在"));
        DomainStatus.getInstance().check(DomainOprationEnum.AGREEMENT_SIGN,agreement.getStatusId());
        //验证客户是否已审核通过
        Customer customer = customerService.getById(agreement.getCustomerId());
        if(!Objects.equals(CustomerStatusEnum.TYPE_2,CustomerStatusEnum.of(customer.getStatusId()))){
            throw new ServiceException("客户公司资料还未审核通过，无法签署供应链服务协议");
        }
        String lockKey = DistributedLockEnum.SERVICE_AGREEMENT_SIGN.getCode() + ":"  + agreement.getCustomerId();
        Lock lock = redisLockRegistry.obtain(lockKey);
        boolean isLock;
        try {
            isLock = lock.tryLock(lockTime, TimeUnit.SECONDS);
            if (!isLock) {
                log.error(StrUtil.format("代客户签署协议未获取到锁，客户id：【{}】，操作人：【{}】"),agreement.getCustomerId(),SecurityUtil.getCurrentPersonName());
                throw new ServiceException("客户协议正在处理中，请勿重复操作");
            }
            confirmAgreement(agreement);
        } catch (InterruptedException e) {
            log.error("签署协议获取锁异常",e);
            throw new ServiceException("服务拥挤，请稍后再试");
        } finally {
            lock.unlock();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void scheduleInvalidImpAgreement() {
        agreementMapper.invalidImpAgreement();
    }

    @Override
    public HSSFWorkbook exportApprovalForm(Long id) {
        Agreement agreement = super.getById(id);
        Optional.ofNullable(agreement).orElseThrow(()->new ServiceException("进口报价不存在"));

        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("进口协议备案表");

        //黑色18号宋体居中
        HSSFCellStyle blackStyle0 = workbook.createCellStyle();
        blackStyle0.setAlignment(HorizontalAlignment.CENTER);
        blackStyle0.setVerticalAlignment(VerticalAlignment.CENTER);
        blackStyle0.setBorderBottom(BorderStyle.THIN);
        blackStyle0.setBorderTop(BorderStyle.THIN);
        blackStyle0.setBorderLeft(BorderStyle.THIN);
        blackStyle0.setBorderRight(BorderStyle.THIN);
        blackStyle0.setWrapText(true);

        //黑色11号宋体居中
        HSSFCellStyle blackStyle1 = workbook.createCellStyle();
        blackStyle1.setAlignment(HorizontalAlignment.CENTER);
        blackStyle1.setVerticalAlignment(VerticalAlignment.CENTER);
        blackStyle1.setBorderBottom(BorderStyle.THIN);
        blackStyle1.setBorderTop(BorderStyle.THIN);
        blackStyle1.setBorderLeft(BorderStyle.THIN);
        blackStyle1.setBorderRight(BorderStyle.THIN);
        blackStyle1.setWrapText(true);

        //红色11号宋体居中
        HSSFCellStyle blackStyle2 = workbook.createCellStyle();
        blackStyle2.setAlignment(HorizontalAlignment.CENTER);
        blackStyle2.setVerticalAlignment(VerticalAlignment.CENTER);
        blackStyle2.setBorderBottom(BorderStyle.THIN);
        blackStyle2.setBorderTop(BorderStyle.THIN);
        blackStyle2.setBorderLeft(BorderStyle.THIN);
        blackStyle2.setBorderRight(BorderStyle.THIN);
        blackStyle2.setWrapText(true);

        HSSFFont blackBoldFont = workbook.createFont();
        blackBoldFont.setFontName("宋体");
        blackBoldFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        blackBoldFont.setFontHeightInPoints((short) 18);
        blackBoldFont.setBold(false);
        blackStyle0.setFont(blackBoldFont);

        HSSFFont blackTitleFont = workbook.createFont();
        blackTitleFont.setFontName("宋体");
        blackTitleFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        blackTitleFont.setFontHeightInPoints((short) 11);
        blackTitleFont.setBold(false);
        blackStyle1.setFont(blackTitleFont);

        HSSFFont redTitleFont = workbook.createFont();
        redTitleFont.setFontName("宋体");
        redTitleFont.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
        redTitleFont.setFontHeightInPoints((short) 11);
        redTitleFont.setBold(false);
        blackStyle2.setFont(redTitleFont);

        HSSFCellStyle blackStyle11 = workbook.createCellStyle();
        blackStyle11.setAlignment(HorizontalAlignment.CENTER);
        blackStyle11.setVerticalAlignment(VerticalAlignment.CENTER);
        blackStyle11.setBorderBottom(BorderStyle.THIN);
        blackStyle11.setBorderTop(BorderStyle.THIN);
        blackStyle11.setBorderLeft(BorderStyle.THIN);
        blackStyle11.setBorderRight(BorderStyle.THIN);
        blackStyle11.setWrapText(true);
        blackStyle11.setFont(blackTitleFont);
        blackStyle11.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
        blackStyle11.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        SubjectVO subjectVO = subjectService.findByCode();
        int rowNum = 0;
        HSSFRow row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        Cell cell = row.createCell(0);
        cell.setCellValue(subjectVO.getName() + "\n" + "进口客户协议审批表");
        cell.setCellStyle(blackStyle0);
        CellRangeAddress region = new CellRangeAddress(0, 0, 0, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (30 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户名称：");
        cell.setCellStyle(blackStyle1);

        Customer customer = customerService.getById(agreement.getCustomerId());
        cell = row.createCell(1);
        cell.setCellValue(customer.getName());
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("协议编号：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue(agreement.getDocNo());
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (30 * 20));
        cell = row.createCell(0);
        cell.setCellValue("进口产品：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue(agreement.getMainProduct());
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("销售人员：");
        cell.setCellStyle(blackStyle1);

        Long salePersonId = customer.getSalePersonId();
        Person salePerson = personService.getById(salePersonId);

        cell = row.createCell(3);
        cell.setCellValue(Optional.ofNullable(salePerson).map(Person::getName).orElse(""));
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (30 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户来源：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("自营客户□ 渠道客户□");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("渠道商名称：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户地址：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue(customer.getAddress());
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        region = new CellRangeAddress(rowNum, rowNum, 1, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("协议生效日期：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue(LocalDateTimeUtils.formatTime(agreement.getEffectDate(),"yyyy-MM-dd"));
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("协议截止日期");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue(LocalDateTimeUtils.formatTime(agreement.getActualInvalidDate(),"yyyy-MM-dd"));
        cell.setCellStyle(blackStyle1);

        List<ImpQuote> impQuotes = impQuoteService.findByAgreementId(agreement.getId());
        //暂只取第一个
        ImpQuote impQuote = impQuotes.get(0);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("业务类型：");
        cell.setCellStyle(blackStyle1);

        QuoteTypeEnum quoteTypeEnum = QuoteTypeEnum.of(impQuote.getQuoteType());
        cell = row.createCell(1);
        cell.setCellValue(quoteTypeEnum.getName());
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("垫税账期：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        if(Objects.equals(QuoteTypeEnum.ADVANCE_CHARGE,quoteTypeEnum)) {
            cell.setCellValue("");
        } else {
            cell.setCellValue(AgreementUtil.getAgreementQuoteDesc(impQuote));
        }

        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("收费标准：");
        cell.setCellStyle(blackStyle1);
        region = new CellRangeAddress(rowNum, rowNum + 1, 0, 0);
        sheet.addMergedRegion(region);

        cell = row.createCell(1);
        cell.setCellValue(TaxTypeEnum.of(impQuote.getTaxType()).getName());
        cell.setCellStyle(blackStyle1);
        region = new CellRangeAddress(rowNum, rowNum + 1, 1, 1);
        sheet.addMergedRegion(region);

        cell = row.createCell(2);
        cell.setCellValue("代理费率：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue(StrUtil.format("{}/单+{}%",impQuote.getBasePrice(),impQuote.getServiceRate()));
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));

        cell = row.createCell(0);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("最低收费：");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue(NumberFormat.getNumberInstance().format(impQuote.getMinCost()));
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("结算模式：");
        cell.setCellStyle(blackStyle1);

        String settementDesc = "";
        if(Objects.equals(BusinessTypeEnum.IMP_AGENT.getCode(),agreement.getBusinessType())) {
            settementDesc = "双抬头结算，海关缴税单客户抵扣，我司开具代理费发票给客户";
        } else {
            settementDesc = "单抬头结算，海关缴税单我司抵扣，我司开具增值税发票及代理费发票给客户";
        }
        cell = row.createCell(1);
        cell.setCellValue(settementDesc);
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        region = new CellRangeAddress(rowNum, rowNum, 1, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("开票模式：");
        cell.setCellStyle(blackStyle1);

        String invoiceDesc = "我司收齐税代费发票后，再开具发票/提供税票给客户";
        cell = row.createCell(1);
        cell.setCellValue(invoiceDesc);
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        region = new CellRangeAddress(rowNum, rowNum, 1, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("其他特殊规则：\n" +
                "（请备注）");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue(impQuoteService.quoteDescribe(impQuote));
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        region = new CellRangeAddress(rowNum, rowNum, 1, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("授信额度");
        cell.setCellStyle(blackStyle1);

        ImpClause impClause = impClauseService.findByAgreementId(agreement.getId());
        cell = row.createCell(1);
        cell.setCellValue(StrUtil.format("税款额度：{}，货款额度：{}", NumberFormat.getNumberInstance().format(impClause.getTaxQuota()) ,NumberFormat.getNumberInstance().format(impClause.getGoodsQuota())));
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        region = new CellRangeAddress(rowNum, rowNum, 1, 3);
        sheet.addMergedRegion(region);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("审批节点");
        cell.setCellStyle(blackStyle11);

        cell = row.createCell(1);
        cell.setCellValue("审核人");
        cell.setCellStyle(blackStyle11);

        cell = row.createCell(2);
        cell.setCellValue("审核时间");
        cell.setCellStyle(blackStyle11);

        cell = row.createCell(3);
        cell.setCellValue("审核意见");
        cell.setCellStyle(blackStyle11);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户协议-销售审批/申请");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户协议-风控审批");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户协议-运营审批");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户协议-财务审批");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        ++rowNum;
        row = sheet.createRow(rowNum);
        row.setHeightInPoints(20);
        row.setHeight((short) (50 * 20));
        cell = row.createCell(0);
        cell.setCellValue("客户协议-总经理审批");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(1);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(2);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        cell = row.createCell(3);
        cell.setCellValue("");
        cell.setCellStyle(blackStyle1);

        //设置列宽
        sheet.setColumnWidth(0, 25 * 256);
        sheet.setColumnWidth(1, 40 * 256);
        sheet.setColumnWidth(2, 25 * 256);
        sheet.setColumnWidth(3, 40 * 256);

        //默认行高
        sheet.setDefaultRowHeightInPoints(20);
        sheet.setDefaultRowHeight((short) (30 * 20));

        return workbook;
    }

    @Override
    public AgreementApprovalVO getPrintApproval(Long id) {
        Agreement agreement = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("协议不存在"));
        AgreementApprovalVO vo = new AgreementApprovalVO();
        AgreementDetailVO agreementDetailVO = beanMapper.map(agreement,AgreementDetailVO.class);
        Customer customer = customerService.getById(agreementDetailVO.getCustomerId());
        agreementDetailVO.setCustomerName(customer.getName());
        agreementDetailVO.setCustomerAddress(customer.getAddress());
        if(Objects.nonNull(customer.getSalePersonId())) {
            Person person = personService.getById(customer.getSalePersonId());
            agreementDetailVO.setSalePersonName(Optional.ofNullable(person).map(Person::getName).orElse(""));
        }
        SubjectVO subjectVO = subjectService.findByCode();
        agreementDetailVO.setSubjectName(subjectVO.getName());
        vo.setAgreement(agreementDetailVO);
        List<ImpQuote> impQuotes =  impQuoteService.findByAgreementId(id);
        ImpClause impClause = impClauseService.findByAgreementId(id);
        ImpQuoteVO impQuoteVO = beanMapper.mapAsList(impQuotes, ImpQuoteVO.class).get(0);
        impQuoteVO.setTaxDesc(AgreementUtil.getAgreementQuoteDesc(beanMapper.map(impQuoteVO,ImpQuote.class)));
        impQuoteVO.setQuoteDesc(impQuoteService.quoteDescribe(beanMapper.map(impQuoteVO,ImpQuote.class)));
        vo.setImpQuote(impQuoteVO);
        vo.setImpClause(Objects.nonNull(impClause) ? beanMapper.map(impClause, ImpClauseVO.class) : null);
        return vo;
    }
}
